﻿#include "PythonAgent.h"

#ifdef Q_OS_WIN32
#include <atlconv.h>
#include <wchar.h>
#endif
#include <locale.h>

#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QTextStream>
#include <QThread>
#include <QDebug>

#include "PyInterpreter.h"
#include "RecordScript.h"
#include "ScriptThread.h"
#include "BaseModule/IBaseSignal.h"
#include "BaseModule/GlobalHelper.h"


namespace ScriptManager
{
    PythonAgent* PythonAgent::m_instance = nullptr;

    PythonAgent* PythonAgent::getInstance()
    {
        if (m_instance == nullptr)
        {
            m_instance = new PythonAgent;
        }

        return m_instance;
    }

    void PythonAgent::appCodeList(QString code)
    {
        if (!m_append) return;
        emit IBaseSignalInstance->signal_showMessageToConsole(BaseModule::EMessageConsole::Script, code);
        m_interpreter->codeListAppend(code);
    }

    PythonAgent::PythonAgent() :
        m_ptrThread(new QThread(this))
    {
        m_interpreter = new PyInterpreter;

    }

    void PythonAgent::initialize()
    {

        QString path = qApp->applicationDirPath() + "/../python37";
        path = QDir::cleanPath(path);
        QByteArray ba = path.toUtf8();
        char* ch = ba.data();
        wchar_t* wc{};

#ifdef Q_OS_WIN32
        //USES_CONVERSION;
        //wc = A2W(ch);
#endif

#ifdef Q_OS_LINUX
        setlocale(LC_CTYPE, "zh_CN.utf8");
        int w_size = mbstowcs(NULL, ba, 0) + 1;
        wc = new wchar_t[w_size];
        mbstowcs(wc, ba, strlen(ba) + 1);
#endif


        QDir d(path);
        if (d.exists())
        {
            if (!m_interpreter->init(this, path))
                emit IBaseSignalInstance->signal_showMessageToConsole(BaseModule::EMessageConsole::Error, tr("Script Initialize failed!"));
            else
                emit IBaseSignalInstance->signal_showMessageToConsole(BaseModule::EMessageConsole::Normal, tr("Script Initialized"));
        }
        else
        {
            emit IBaseSignalInstance->signal_showMessageToConsole(BaseModule::EMessageConsole::Error,
                tr("Python37 directory does not exist in application directory, please check!"));
        }

        m_recordScript = new RecordThread;
        m_recordScript->start();
    }

    void PythonAgent::finalize()
    {
        if (m_scriptThread)
        {
            if (m_scriptThread->isRunning())
            {
                m_scriptThread->stop();
                m_scriptThread->quit();
                m_scriptThread->wait();
            }
            while (m_scriptThread->isRunning());
            delete m_scriptThread;
            m_scriptThread = nullptr;
        }

        if (m_recordScript)
        {
            m_recordScript->stop();
            m_recordScript->quit();
            m_recordScript->wait();
            delete m_recordScript;
        }

        if (m_interpreter)
        {
            delete m_interpreter;
        }

    }

    void PythonAgent::execCode(QString code, bool save, bool exec)
    {
        if (code.isEmpty())
        {
            return;
        }
        emit IBaseSignalInstance->signal_showMessageToConsole(BaseModule::EMessageConsole::Script, code);
        if (exec)//执行时自动保存
        {
            int _isOK = m_interpreter->execCode(code, save);
            emit IBaseSignalInstance->signal_excuteScript(code);
            if (_isOK == -1)
            {
                if (m_scriptThread)
                {
                    m_scriptThread->releaseLock();
                }
            }
        }
        else if (save)//只保存不执行
        {
            m_interpreter->codeListAppend(code);
        }
    }

    void PythonAgent::execCode(QStringList codes, bool save, bool exec)
    {
        const int n = codes.size();
        for (int i = 0; i < n; ++i)
        {
            this->execCode(codes.at(i), save, exec);
        }
    }

    void PythonAgent::submit(QString code, bool save, bool exec)
    {
        if (m_scriptThread)
        {
            emit IBaseSignalInstance->signal_showMessageToConsole(BaseModule::EMessageConsole::Warning,
                QObject::tr("python is Locked,Please try again later,code :%1").arg(code));
            return;
        }
        execCode(code, save, exec);
    }

    void PythonAgent::submit(QStringList codes, bool save, bool exec)
    {
        if (m_scriptThread)
        {
            emit IBaseSignalInstance->signal_showMessageToConsole(BaseModule::EMessageConsole::Warning,
                QObject::tr("python is Locked,Please try again later,code :%1").arg(codes.join(";")));
            return;
        }
        const int n = codes.size();
        for (int i = 0; i < n; ++i)
        {
            this->execCode(codes.at(i), save, exec);
        }
    }

    void PythonAgent::submitFromScriptThread(QString code, bool save, bool exec)
    {
        execCode(code, save, exec);
    }

    void PythonAgent::submitFromScriptThread(QStringList codes, bool save, bool exec)
    {
        execCode(codes, save, exec);
    }

    void PythonAgent::saveScript(QString fileName)
    {
        QFile file(fileName);
        if (!file.open(QIODevice::Text | QIODevice::WriteOnly))
        {
            emit IBaseSignalInstance->signal_showMessageToConsole(BaseModule::EMessageConsole::Error, tr("Script open failed"));
            return;
        }
        QTextStream stream(&file);
        stream.setCodec("UTF-8");
        const int n = m_interpreter->getCodeCount();
        for (int i = 0; i < n; ++i)
        {
            QString s = m_interpreter->getCodeAt(i);
            stream << s << endl;
        }
        file.close();
        emit IBaseSignalInstance->signal_UpdateStatusBarInformation(QStringLiteral("保存脚本成功！"), false);
        emit IBaseSignalInstance->signal_showMessageToConsole(BaseModule::EMessageConsole::Normal, tr("Script Saved %1").arg(fileName));
    }

    bool PythonAgent::execScriptFile(QString fileName, bool isNoGui, QStringList listPara)
    {
        if (m_scriptThread)
        {
            emit IBaseSignalInstance->signal_showMessageToConsole(BaseModule::EMessageConsole::Error,
                tr("There is already a python script being executed, please try again later!"));
            return false;
        }
        m_scriptThread = new ScriptThread(this, fileName, isNoGui);
        m_scriptThread->setPara(listPara);
        connect(m_scriptThread, SIGNAL(finished()), this, SLOT(readerFinished()));
        m_scriptThread->start();
        return true;
    }

    bool PythonAgent::execScriptCode(QStringList listCode, bool isNoGUI, QStringList listPara)
    {
        if (m_scriptThread)
        {
            return false;
        }
        m_scriptThread = new ScriptThread(this, listCode, isNoGUI);
        m_scriptThread->setPara(listPara);
        connect(m_scriptThread, SIGNAL(finished()), this, SLOT(readerFinished()));
        m_scriptThread->start();
        return true;
    }

    void PythonAgent::readerFinished()
    {
        if (m_scriptThread)
        {
            delete m_scriptThread;
            m_scriptThread = nullptr;
        }
        //if(m_recordScript)
        //    m_recordScript->reStart();

        if (!m_isGUI)
        {
            emit IBaseSignalInstance->signal_closeApp();
        }
    }

    void PythonAgent::lock()
    {
        if (m_scriptThread != nullptr)
        {
            m_scriptThread->recordLock();
        }
    }

    void PythonAgent::unLock()
    {
        if (m_scriptThread != nullptr)
        {
            m_scriptThread->releaseLock();
        }
    }

    bool PythonAgent::isLocked()
    {
        return m_islock;
    }

    QStringList PythonAgent::getcodelist()
    {
        if (m_interpreter)
        {
            return m_interpreter->getCode();
        }
        return QStringList();
    }

    void PythonAgent::setIsGUI(bool isGui)
    {
        m_isGUI = isGui;
    }

    void PythonAgent::appendOn()
    {
        m_append = true;
    }

    void PythonAgent::appendOff()
    {
        m_append = false;
    }

    void PythonAgent::execMessWinCode(QString code)
    {
        m_interpreter->execCode(code);
    }

    void PythonAgent::backstageExec(QString code)
    {
        m_interpreter->execCode(code, false);
    }

    void PythonAgent::stopScript()
    {
        if (m_scriptThread && !m_isDebug)
        {
            m_scriptThread->stop();
        }
    }

    void PythonAgent::setDebug(bool isDebug)
    {
        m_isDebug = isDebug;
    }

    bool PythonAgent::appendCommandToPyThread(QString filePath, QStringList command)
    {
        if (!m_scriptThread)
        {
            return false;
        }
        else
        {
            return m_scriptThread->appendCommand(filePath, command);
        }

    }

    bool PythonAgent::isScriptRuning()
    {
        if (!m_scriptThread)
        {
            return false;
        }
        else
        {
            return m_scriptThread->isRunning();
        }
    }

    void PythonAgent::setIsImportExample()
    {
        if (m_scriptThread)
        {
            m_scriptThread->setIsImportExample();
        }
    }

    void PythonAgent::restartRecordScript()
    {
        if (m_interpreter && m_recordScript)
        {
            m_interpreter->clearCode();
            m_recordScript->reStart();
            emit IBaseSignalInstance->signal_showMessageToConsole(BaseModule::EMessageConsole::Normal, QObject::tr("Restart the recording script!"));
        }
    }

}
